﻿#include "string.h"
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "spi.h"
#include "ASM330.h"
#include "time.h"
#include "BG35.h"
#include "tool.h"
#include "stm32f10x_usart.h"
#include "TurnTable.h"

typedef struct
{
  unsigned char dataPackageType; //数据包类型
  unsigned short dataMsgId;      //消息ID
  unsigned int dataDeviceId;     //数据包设备ID
  unsigned short timeStamp;      //时间戳
  unsigned char *dataPtr;        //载荷指针
  unsigned short dataSize;       //载荷大小
} DataPackageInfo;

//枚举类占用大小过大，这里使用unsigned char型常量代替
//-----------------------WorkType--------------------
const unsigned char WorkType_ReadingMEMS = 0x01; //单片机工作状态，读取传感器数据
const unsigned char WorkType_SendingAT = 0x02;   //单片机工作状态，发送AT指令
const unsigned char WorkType_Decoding = 0x04;    //单片机工作状态，编码
//---------------------------------------------------

//--------------------DataPackageType--------------------
const unsigned char DataPackageType_HeartBeat = 0x00;  //数据包类型，心跳
const unsigned char DataPackageType_SensorData = 0x01; //数据包类型，传感器数据
const unsigned char DataPackageType_TurnTable = 0x02;  //数据包类型，转台数据
const unsigned char DataPackageType_MCUCtrl = 0x03;    //数据包类型，单片机数据
const unsigned char DataPackageType_Register = 0x04;   //数据包类型，注册数据
const unsigned char DataPackageType_Test = 0x05;   //数据包类型，测试
const unsigned char DataPackageType_Size = 0x06;       //数据包类型枚举的数量
void (*UDP_decode_fun[DataPackageType_Size])(DataPackageInfo *);
//-------------------------------------------------------

//---------------------MCUCtrlType-----------------------
const unsigned char MCUCtrlType_SetInterval_MEMSData = 0x00; //MCU控制类型，设置MEMS数据发送间隔
//-------------------------------------------------------

//---------------------RegisterType----------------------
const unsigned char RegisterType_Logout = 0x00; //注册类型，登出
const unsigned char RegisterType_Login = 0x01;  //注册类型，登入
const unsigned char RegisterType_Reset = 0x02; //注册类型，重置
const unsigned char RegisterType_Size = 0x03;   //注册类型枚举的数量
//-------------------------------------------------------

unsigned char sendDataBuffer[300];      //发送数据缓冲区，用于缓存要发送的UDP源数据
unsigned short sendDataBuffer_size = 0; //发送数据缓冲区大小，用于确定UDP源数据的长度，避免源数据中的0x00打断发送过程
unsigned short msgId = 0;               //消息ID，用于填写UDP报文中的消息ID字段
unsigned int deviceId = 100000;         //设备ID，用于设备鉴权

//--------------------标志位------------------------
BOOL connectionState = FALSE;  //连接状态标志位，用于记录当前连接状态
BOOL isSendUDPAckData = FALSE; //表示是否发送确认反馈
//-------------------------------------------------

//--------------------计时器------------------------
unsigned short minInterval_readMEMSData = 1000; //最小读取数据间隔
unsigned short interval_heartBeat = 23000;      //心跳间隔
unsigned short interval_readMEMSData = 3000;    //读取传感器数据间隔
unsigned short remainTime_heartBeat = 0;        //心跳发送剩余时间
unsigned short remainTime_readMEMSData = 0;     //读取传感器数据剩余时间
//-------------------------------------------------

//---------------------消息ID记录-------------------
unsigned short msgId_heartBeat = 0;     //记录最近已发送的心跳包的消息ID，用于确认数据包反馈
unsigned short msgId_sensorData = 0;    //记录最近已发送的传感器数据的消息ID
unsigned short msgId_turnTableData = 0; //记录最近已发送的转台数据的消息ID
unsigned short msgId_mCUCtrl = 0;       //记录最近的已发送的单片机控制数据的消息ID
unsigned short msgId_register = 0;      //记录最近的已发送的注册数据的消息ID，用于确认数据包反馈
//-------------------------------------------------

void clock() //时钟控制
{
  delay_ms(1);                                                                 //时钟的基本单位是毫秒
  (0 == remainTime_readMEMSData) ? TRUE : --remainTime_readMEMSData;           //读传感器剩余时间，减少一个时钟单位
  (0 == remainTime_heartBeat) ? TRUE : --remainTime_heartBeat;                 //心跳发送剩余时间，减少一个时钟单位
  (0 == remainTime_isRSP_timeout) ? TRUE : --remainTime_isRSP_timeout;         //NB模组响应超时时间，减少一个时钟单位
  //  (0 == remainTime_sendTurnTableData) ? TRUE : --remainTime_sendTurnTableData; //转台发送数据时间间隔，减少一个时钟单位
  //  (0 == remainTime_getCurrentState) ? TRUE : --remainTime_getCurrentState; //转台查询当前状态时间间隔，减少一个时钟单位
  //  (0 == remainTime_getRunningState) ? TRUE : --remainTime_getRunningState; //转台查询运行状态时间间隔，减少一个时钟单位
}

void readMEMSData(unsigned char *buffer) //读取传感器数据到指定缓冲区buffer
{
  unsigned char mEMSDataBuffer[14]; //采集数据缓冲区，用于缓存传感器14字节的源数据
  unsigned char mEMSDataBuffer_size = sizeof(mEMSDataBuffer);
  if (0x6B == statu1) //读取第一个ASM330
    {
      memset(mEMSDataBuffer, 0, mEMSDataBuffer_size);                                    //初始化采集数据缓冲区
      USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);                                    //关闭串口中断
      ASM330_Read_Buf(ASM330LHH_OUT_TEMP_L, mEMSDataBuffer, mEMSDataBuffer_size, SPI_1); //读取缓冲区的值
      USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);                                     //开启串口中断
      USART1_IRQHandler();                                                               //读串口数据，看是否有数据
      ASM330_ChangeData_SPI1(mEMSDataBuffer, buffer, 0);                                 //转化成报文数据格式
    }
  if (0x6B == statu2) //读取第二个ASM330
    {
      memset(mEMSDataBuffer, 0, mEMSDataBuffer_size);                                    //初始化采集数据缓冲区
      USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);                                    //关闭串口中断
      ASM330_Read_Buf(ASM330LHH_OUT_TEMP_L, mEMSDataBuffer, mEMSDataBuffer_size, SPI_2); //读取缓冲区的值
      USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);                                     //开启串口中断
      USART1_IRQHandler();                                                               //读串口数据，看是否有数据
      ASM330_ChangeData_SPI2(mEMSDataBuffer, buffer, 0);                                 //转化成报文数据格式
    }
  if (0x6B == statu3) //读取第三个ASM330
    {
      memset(mEMSDataBuffer, 0, mEMSDataBuffer_size);                                    //初始化采集数据缓冲区
      USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);                                    //关闭串口中断
      ASM330_Read_Buf(ASM330LHH_OUT_TEMP_L, mEMSDataBuffer, mEMSDataBuffer_size, SPI_3); //读取缓冲区的值
      USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);                                     //开启串口中断
      USART1_IRQHandler();                                                               //读串口数据，看是否有数据
      ASM330_ChangeData_SPI3(mEMSDataBuffer, buffer, 0);                                 //转化成报文数据格式
    }
  if (0x6B == statu4) //读取第四个ASM330
    {
      memset(mEMSDataBuffer, 0, mEMSDataBuffer_size);                                    //初始化采集数据缓冲区
      USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);                                    //关闭串口中断
      ASM330_Read_Buf(ASM330LHH_OUT_TEMP_L, mEMSDataBuffer, mEMSDataBuffer_size, SPI_4); //读取缓冲区的值
      USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);                                     //开启串口中断
      USART1_IRQHandler();                                                               //读串口数据，看是否有数据
      ASM330_ChangeData_SPI4(mEMSDataBuffer, buffer, 0);                                 //转化成报文数据格式
    }
}

void UDP_decode_heartBeat(DataPackageInfo *dataPackageInfo)
{
  //心跳包由服务器发给设备，服务器要根据时间戳来计算发包频率
  //收到心跳包，返回反馈，重置超时时间
  if(dataPackageInfo->dataDeviceId == deviceId)//若设备ID与自身的设备ID相等
    {
      if(TRUE==connectionState)//只有在连接状态才对心跳包做出反馈
        {
          isSendUDPAckData = TRUE;//发送反馈
          remainTime_heartBeat = interval_heartBeat;//重置超时时间
        }
    }
}

void UDP_decode_sensorData(DataPackageInfo *dataPackageInfo)
{
  (void)dataPackageInfo;
  //传感器数据的回复，表示服务器已经收到对应的传感器数据
}

void UDP_decode_turnTable(DataPackageInfo *dataPackageInfo)
{
  //转台数据回复，表示服务器已经收到转台数据
  //转台数据命令，服务器发出的转台命令，需要对该命令做出回复
  isSendUDPAckData = TRUE;                                         //发送反馈报文
  TurnTable_appendTurnTableDataToSendQueue(dataPackageInfo->dataPtr); //将要发送给转台的数据添加到转台发送队列
}

void UDP_decode_mCUCtrl(DataPackageInfo *dataPackageInfo)
{
  //服务器向设备发送MCU控制报文，用于控制MCU的行为
  //收到该报文后需要向服务器发送反馈
  //MCU控制行为应设计为多次执行结果一致，避免因为丢包导致的行为不一致
  if (MCUCtrlType_SetInterval_MEMSData == dataPackageInfo->dataPtr[0])
    {
      interval_readMEMSData = *(unsigned short *)(dataPackageInfo->dataPtr + 1);
      if (minInterval_readMEMSData > interval_readMEMSData)
        {
          interval_readMEMSData = minInterval_readMEMSData; //如果设置时间小于最小间隔则设置为最小间隔
        }
      if (interval_readMEMSData <= remainTime_readMEMSData)
        {
          remainTime_readMEMSData = interval_readMEMSData;
        }
      isSendUDPAckData = TRUE; //发送反馈报文
    }
}

void UDP_decode_register(DataPackageInfo *dataPackageInfo)
{
  //因为存在其他数据包触发的重注册消息，数据包ID会比当前注册消息ID要大
  //应取大于(心跳间隔)*10以上的差值来判定消息ID的合法性
  //若数据包ID减去当前注册消息ID小于100，则认为合法
  if (((dataPackageInfo->dataMsgId - msgId_register) & 0xffff) > 100)
    {
      return;
    }
  remainTime_heartBeat = interval_heartBeat;                                //收到注册包回应被视为收到心跳包
  if (RegisterType_Login == dataPackageInfo->dataPtr[0]) //数据体第一个字节为0x01时代表登入成功
    {
      connectionState = TRUE; //将当前状态更改为在线
      return;
    }
  if(RegisterType_Reset == dataPackageInfo->dataPtr[0])//重置连接反馈
    {
      connectionState = FALSE;  //将当前状态更改为离线
      remainTime_heartBeat = 0; //心跳剩余时间归零，方便第一时间发送注册报文
    }
}

void UDP_decode_test(DataPackageInfo *dataPackageInfo)
{
  (void)dataPackageInfo;
  isSendUDPAckData = TRUE;
}

void UDP_decode()
{
  char udpData[300];              //udp数据缓冲区,用于存放需要解析的UDP数据
  unsigned short udpDataSize = 0; //udp数据缓冲区大小
  unsigned char headSize = 0;     //头部数据大小
  unsigned int dataDeviceId = 0;  //设备Id
  DataPackageInfo dataPackageInfo;
  memset(udpData, 0, sizeof(udpData));                  //初始化缓冲区
  BG35_getDataFromUdpDataBuffer(udpData, &udpDataSize); //从BG35的UDP数据缓冲区中得到UDP源数据
  if (0 == udpDataSize)                                 //若缓冲区大小为0，则代表没有数据，返回
    {
      return;
    }
  //解析头部
  dataPackageInfo.dataPackageType = udpData[headSize];                       //解析数据包类型
  ++headSize;
  dataPackageInfo.dataMsgId = *(unsigned short *)(udpData+headSize); //解析msgId
  headSize += sizeof (dataPackageInfo.dataMsgId);                                     //头部偏移增加
  dataDeviceId = *(unsigned int *)(udpData + headSize);                             //解析设备Id
  headSize += sizeof (dataDeviceId);             //头部偏移增加
  dataPackageInfo.timeStamp = *(unsigned short *)(udpData+headSize);//解析timestamp
  headSize += sizeof (dataPackageInfo.timeStamp);
  //头部解析完毕
  if (headSize > udpDataSize) //若udp数据缓冲区小于头部大小，则返回
    {
      return;
    }                                                              //记录头部大小
  dataPackageInfo.dataPtr = (unsigned char *)(udpData + headSize); //载荷指针指向负载开始的地方
  dataPackageInfo.dataSize = udpDataSize - headSize;             //计算载荷大小
  if (dataDeviceId != deviceId)                                  //若数据包中的设备Id与本设备的Id不一致，则丢弃
    {
      return;
    }
  //初步解析完毕
  //开始解析载荷
  if (DataPackageType_Size <= dataPackageInfo.dataPackageType)
    {
      return; //若数据包类型超过限制则丢弃
    }
  UDP_decode_fun[dataPackageInfo.dataPackageType](&dataPackageInfo);
  if (isSendUDPAckData)
    {
      isSendUDPAckData = FALSE;
      BG35_AT_NSOST(udpData, headSize);
    }
}

void UDP_codeHead(const unsigned char dataPackageType) //编码UDP数据包的头部
{
  memset(sendDataBuffer, 0, sizeof(sendDataBuffer));                        //初始化发送数据缓冲区
  sendDataBuffer_size = 0;                                                  //初始化发送数据缓冲区大小
  sendDataBuffer[sendDataBuffer_size] = dataPackageType; //填入数据包类型字段和消息ID的前部分
  ++sendDataBuffer_size;
  *(unsigned short *)(sendDataBuffer+sendDataBuffer_size) = msgId;
  sendDataBuffer_size += sizeof (msgId);
  ++msgId;                                              //计算出下一个消息ID
  *((unsigned int *)(sendDataBuffer + sendDataBuffer_size)) = deviceId;     //填入设备ID标志位
  sendDataBuffer_size += sizeof (deviceId);                                                 //发送数据缓冲区大小增加
}

void UDP_sendHeartBeat() //发送心跳报文
{
  remainTime_heartBeat = interval_heartBeat;                  //将心跳剩余时间置为设置的时间间隔
  msgId_heartBeat = msgId;                                    //记录当次心跳的消息ID用于确认反馈
  UDP_codeHead(DataPackageType_HeartBeat);                    //编码心跳包的头部
  BG35_AT_NSOST((char *)sendDataBuffer, sendDataBuffer_size); //通过AT指令发送数据
}

void UDP_sendSensorData() //发送传感器报文
{
  remainTime_readMEMSData = interval_readMEMSData; //将发送传感器数据剩余时间置为设置的时间间隔
  //帧头处理
  //发送传感器数据时的msgId记录以后考虑多组式
  UDP_codeHead(DataPackageType_SensorData);                   //编码传感器数据头部
  readMEMSData(sendDataBuffer + sendDataBuffer_size);         //读取传感器数据
  sendDataBuffer_size += 68;                                  //发送数据缓冲区大小增加
  BG35_AT_NSOST((char *)sendDataBuffer, sendDataBuffer_size); //通过AT指令发送数据
}

void UDP_sendTurnTableData() //发送转台数据
{
  if (TurnTable_isDataBufferEmpty()) //若转台数据缓冲区是空的则返回
    {
      return;
    }
  UDP_codeHead(DataPackageType_TurnTable);                           //编码转台数据头部
  TurnTable_dataBufferGetData(sendDataBuffer + sendDataBuffer_size); //得到要发送的砖塔数据
  sendDataBuffer_size += 16;                                         //发送数据缓冲区大小增加
  BG35_AT_NSOST((char *)sendDataBuffer, sendDataBuffer_size);        //通过AT指令发送数据
}

void UDP_sendRegisterData() //发送注册数据
{
  remainTime_heartBeat = interval_heartBeat;                  //将发送心跳剩余时间置为设置的间隔
  msgId_register = msgId;                                     //记录当前消息ID用于确认反馈报文
  UDP_codeHead(DataPackageType_Register);                     //编码注册数据头部
  sendDataBuffer[sendDataBuffer_size++] = RegisterType_Login; //填入代表注册请求的数据
  BG35_AT_NSOST((char *)sendDataBuffer, sendDataBuffer_size); //通过AT指令发送数据
}

void init()
{
  Sensor_SPI_Init(); //传感器与主板的SPI通信配置初始化
  delay_init();      //初始化延时函数
  uart_init(460800); //PC端与主板的串口波特率配置初始化
  //  TurnTable_uart_init();//初始化转台串口
  //ASM330LHH 初始化
  //  ASM330_RESET_SET(Deviece_Reset, Decice_Conf); //软件复位与硬件配置位设置为1
  //  ASM330_DataUpdate_FullScale_Set(ASM330LHH_XL_ODR_1667Hz,
  //                                  ASM330LHH_GY_ODR_1667Hz,
  //                                  ACCEL_FS_XL_8g, FS_G_500dps); //设置加计 陀螺采样率 和量程
  //  ASM330_User_Ctrl(ASM330_I2C_IF_DIS);                          //禁用IIC

  //-----------------------禁用--------------------------------------------------------------------------
  //ASM330_LPF1_bandwidth(Trigger_mode_OFF,ASM330LHH_LPF1_FTYPE1);//Gyroscope LPF1 bandwidth selection 222Hz , set CTRL6 reg
  //ASM330_LPF2_path_set(LOW_Pass_ODR_DIV_4);                     //加速度计低通带宽设置  6667/4 Hz
  //----------------------------------------------------------------------------------------------------
  INT2_Update(0X02);
  Dataready_Pulsed(0X80);
  TIM3_Int_Init(50000 - 1, 720 - 1);
  BG35_init(); //初始化BG35
  //  TurnTable_init();//初始化转台
  //-------------------------初始化函数数组----------------------------
  UDP_decode_fun[DataPackageType_HeartBeat] = &UDP_decode_heartBeat;
  UDP_decode_fun[DataPackageType_SensorData] = &UDP_decode_sensorData;
  UDP_decode_fun[DataPackageType_TurnTable] = &UDP_decode_turnTable;
  UDP_decode_fun[DataPackageType_MCUCtrl] = &UDP_decode_mCUCtrl;
  UDP_decode_fun[DataPackageType_Register] = &UDP_decode_register;
  UDP_decode_fun[DataPackageType_Test] = &UDP_decode_test;
  //-----------------------------------------------------------------

  //-------------------------初始化连接-------------------------------
  BG35_waitForBaseStationConnect(0);             //等待基站连接
  BG35_AT_NSOCR();                               //开启BG35的socket
  BG35_waitForOpenSocket(0);                     //等待socket的开启
  //----------------------------------------------------------------
}

int main(void)
{
  init();   //初始化
  while (1) // 主循环开始
    {
      BG35_decode();                    //尝试解析NB模组的数据
      BG35_sendData_queue();            //尝试发送NB数据
      //    TurnTable_decode();               //尝试解析转台数据
      //    TurnTable_sendDataToTurnTable();  //尝试发送转台数据
      //    TurnTable_getTurnTableState(); //查询转台当前状态
      if (!BG35_isUdpDataBufferEmpty()) //UDP数据缓冲区不为空
        {
          UDP_decode(); //解析UDP数据
        }
      if (!TurnTable_isDataBufferEmpty()) //若转台数据缓冲区不为空则发送
        {
          UDP_sendTurnTableData(); //将转台数据添加到NB数据发送队列
        }
      if (0 == remainTime_heartBeat) //连接超时
        {
          UDP_sendRegisterData(); //发送连接请求
          BG35_AT_NSORF(NULL, NULL); //防止异常情况出现导致的阻塞，每到要发送心跳的时候进行读取。
        }
      if (TRUE == connectionState) //只有在连接状态才可以正常进行业务
        {
          if (0 == remainTime_readMEMSData) //剩余时间为零时，读取MEMS数据
            {
              //UDP_sendSensorData();
            }
        }
      clock(); //时钟
    }
}
